<?php
/**
 * templates parser
 * @static
 * Django's templating engine (partial) PHP implementation
 * @link http://djangoproject.com Django
 * this file is from a webappkit package (kit)
 * @link http://webappkit.net
 * @package djtpl
 * @author J.Ducastel <nospam0@ducastel.name>
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 */
class djtplParser {

	/**
	* splits template string into tokens.
	* @static
	* @param string $str
	* @return array
	*/
	function tokenize(&$str) {
		$regex='/({%[^{}]+%})|({{[^{}]+}})/';
		$tokens=preg_split($regex,$str,-1,PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
		for ($n=0; $n<count($tokens); $n++) {
			$tokens[$n]=&new djtplToken($tokens[$n]);
		}
		// print_r($tokens);
		return $tokens;
	}/**/

	/**
	* Builds next node from tokens array
	* @static
	* @param array &$tokens
	* @access public
	* @return djtplNode
	*/
	function & tokensToNode(&$tokens) {
		// infinite loop protection
		static $ifni;
		$ifni++;
		if ($ifni>1000) {
			trigger_error("infinite loop ?");
			exit;
		}
		// preparing to build node
		$node=false;
		// checking next token
		if (!$token=array_shift($tokens) or !is_a($token,'djtplToken'))
			return $node;
		// building upon token type
		switch ($token->getType()) {
			case 'text':
				$node=new djtplTextNode();
				$node->buildFromTokens($token);
				break;
			case 'var':
				$node=new djtplVarNode();
				$node->buildFromTokens($token);
				break;
			case 'tag':
				// is tag registered ?
				$tag=$token->getTagName();
				$class=djtplParser::getTagNodeClass($tag);
				//$registered_tags=djangoTplParser::tags();
				if (class_exists($class)) {
					// building appropriate node
					$node=&new $class();
					$node->buildFromTokens($token,$tokens);
					break;
				}
				// unknown/unsupported tag, defaulting
				$node=&new djtplTagNode();
				$node->buildFromTokens($token,$tokens);
				break;
			default:
				break;
		}
		return $node;
	}/**/

	/**
	* defines tag node class upon tag name
	* @param string $tag
	* @access public
	* @return string
	*/
	function getTagNodeClass($tag) {
		return 'djtpltagnode_'.$tag;
	}/**/

	/**
	* build nodes from tokens until it reaches defined ending tag
	* @static
	* @param array &$tokens djtplToken
	* @param string $closingTag may accept several closing tags, separated by space
	* @access public
	* @return array djtplNode
	*/
	function tokensToNodesUntilTag(&$tokens,$endtag='end') {
		$n=0; $nodes=array();
		// $endtags=explode(' ',$endtagsdef); echo "<p>$endtag</p>";
		while ($node=&djtplParser::tokensToNode($tokens)) {
			// infinite loop protection
			$n++; if ($n>500) break;
			// is node expected end tag ?
			if ($node->isTag($endtag)) {
				// reached closing tag
				// echo '<p>reached '.$endtag.'</p>';
				//return true;
				break;
			}
			$nodes[]=&$node;

		}
		return $nodes;
	}/**/

	/**
	* apply filter to value, or return value if failed
	* @static
	* @param mixed $value
	* @param string $filter filter definition
	* @access public
	* @return mixed
	*/
	function applyFilter($value,$filter) {
		// parsing filter
		if (!ereg('^([^:]*)(:"(.*)")?$',$filter,$search)) {
			trigger_error("invalid filter $filter");
			return $value;
		}
		//echo wakdebug::vardump($search);
		$filterFunc=$search[1];
		$filterArg=$search[3];
		// searching for function
		if (function_exists('djtplfilter_'.$filterFunc)) {
			// using custom djangotpl filter func
			$func='djtplfilter_'.$filterFunc;
		} else if (function_exists($filterFunc)) {
			// backing to php native func
			$func=$filterFunc;
		} else {
			// no function found
			trigger_error("no function found for $filterFunc");
			return $value;
		}
		// function call with or without arg
		if ($filterArg) {
			$value=$func($value,$filterArg);
		} else {
			$value=$func($value);
		}
		return $value;
	}/**/

	/**
	* evals expression and return value
	* @static
	* expression may be path, quoted string
	* @param djtplContext &$context
	* @param string $expr expression to eval
	* @access public
	* @return mixed
	*/
	function evalExpression(&$context,$expr) {
		//echo "<p>djangoTplParser::evalExpression($expr)</p>";
		$value=null;
		// is quoted string ?
		if (ereg('^"(.*)"$',$expr,$search))
			return $search[1];
		// is integer ?
		if (ereg('^[0-9]+$',$expr))
			return intval($expr);
		// is constant
		if (defined($expr))
			return constant($expr);
		// is var
		$value=$context->getpath($expr);
		if (!is_null($value))
			return $value;
		// echo wakdebug::vardump($value);
		//echo "<p>no value for $expr !</p>";
		return $value;
	}/**/

}
